﻿using System;
using System.Collections.Generic;
using System.Text;
using ExcelDataReader;

namespace ExcelToApi
{
    class ApiGenerator
    {
        private enum EnExcelRowType
        {
            /// <summary>描述</summary>
            Description = 0,
            /// <summary>数据</summary>
            Data = 1,
        }

        private enum EnExcelColumnType
        {
            /// <summary>字段类型</summary>
            Type = 0,
            /// <summary>字段名</summary>
            Name = 1,
            /// <summary>字段注释</summary>
            Annotation = 2,
        }

        private string mExportPath = "";
        private string mClassName = "";
        private string mApi = "";

        private List<string> mRequestTypeList = new List<string>();
        private List<string> mRequestNameList = new List<string>();
        private List<string> mRequestAnnotationList = new List<string>();

        private List<string> mResponseTypeList = new List<string>();
        private List<string> mResponseNameList = new List<string>();
        private List<string> mResponseAnnotationList = new List<string>();

        private StringBuilder stringBuilder = new StringBuilder();

        public void GenerateScript(FileSystemInfo pFileSystemInfo, string pExportPath)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            FileStream stream = File.OpenRead(pFileSystemInfo.FullName);
            IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);

            mExportPath = pExportPath;
            mClassName = pFileSystemInfo.Name.Replace(".xlsx", "");

            do
            {
                if (excelReader.Name == "Api")
                    ParseApi(excelReader);
                else if (excelReader.Name == "Request")
                    ParseRequest(excelReader);
                else if (excelReader.Name == "Response")
                    ParseResponse(excelReader);

            } while (excelReader.NextResult());

            GenerateCode();
            ExportFile();
        }

        private void ParseApi(IExcelDataReader pExcelReader)
        {
            pExcelReader.Read();
            mApi = pExcelReader.GetString(0);
        }

        private void ParseRequest(IExcelDataReader pExcelReader)
        {
            mRequestTypeList.Clear();
            mRequestNameList.Clear();
            mRequestAnnotationList.Clear();

            while (pExcelReader.Read())
            {
                if (pExcelReader.Depth > (int)EnExcelRowType.Description)
                {
                    for (int i = 0; i < pExcelReader.FieldCount; i++)
                    {
                        string data = pExcelReader.GetString(i);

                        if (i == (int)EnExcelColumnType.Type)
                            mRequestTypeList.Add(data);
                        else if (i == (int)EnExcelColumnType.Name)
                            mRequestNameList.Add(data);
                        else if (i == (int)EnExcelColumnType.Annotation)
                            mRequestAnnotationList.Add(data);
                    }
                }
            }
        }

        private void ParseResponse(IExcelDataReader pExcelReader)
        {
            mResponseTypeList.Clear();
            mResponseNameList.Clear();
            mResponseAnnotationList.Clear();

            while (pExcelReader.Read())
            {
                if (pExcelReader.Depth > (int)EnExcelRowType.Description)
                {
                    for (int i = 0; i < pExcelReader.FieldCount; i++)
                    {
                        string data = pExcelReader.GetString(i);

                        if (i == (int)EnExcelColumnType.Type)
                            mResponseTypeList.Add(data);
                        else if (i == (int)EnExcelColumnType.Name)
                            mResponseNameList.Add(data);
                        else if (i == (int)EnExcelColumnType.Annotation)
                            mResponseAnnotationList.Add(data);
                    }
                }
            }
        }

        private void GenerateCode()
        {
            stringBuilder.Clear();
            stringBuilder.Append("/*Auto-create script.\n");
            stringBuilder.Append(" * Don't Edit it. */\n");
            stringBuilder.Append("\n");
            stringBuilder.Append("using System.Collections;\n");
            stringBuilder.Append("using System.Collections.Generic;\n");
            stringBuilder.Append("\n");
            stringBuilder.Append("namespace Game.Data.Api\n");
            stringBuilder.Append("{\n");

            stringBuilder.AppendFormat("\tpublic class {0}\n", mClassName);
            stringBuilder.Append("\t{\n");
            stringBuilder.AppendFormat("\t\tpublic const string Api = \"{0}\";\n", mApi);
            stringBuilder.Append("\t}\n");
            stringBuilder.Append("\n");

            stringBuilder.AppendFormat("\tpublic class {0}Request\n", mClassName);
            stringBuilder.Append("\t{\n");
            for (int i = 0; i < mRequestNameList.Count; i++)
            {
                stringBuilder.AppendFormat("\t\t/// <summary>{0}</summary>\n", mRequestAnnotationList[i]);
                stringBuilder.AppendFormat("\t\tpublic {0} {1} {{ get; set; }}\n", mRequestTypeList[i], mRequestNameList[i]);
            }
            stringBuilder.Append("\t}\n");
            stringBuilder.Append("\n");

            stringBuilder.AppendFormat("\tpublic class {0}Response\n", mClassName);
            stringBuilder.Append("\t{\n");
            for (int i = 0; i < mResponseTypeList.Count; i++)
            {
                stringBuilder.AppendFormat("\t\t/// <summary>{0}</summary>\n", mResponseAnnotationList[i]);
                stringBuilder.AppendFormat("\t\tpublic {0} {1} {{ get; set; }}\n", mResponseTypeList[i], mResponseNameList[i]);
            }
            stringBuilder.Append("\t}\n");

            stringBuilder.Append("}");
        }

        /// <summary>输出文件</summary>
        private void ExportFile()
        {
            if (!Directory.Exists(mExportPath))
            {
                Directory.CreateDirectory(mExportPath);
            }

            string path = string.Format("{0}/{1}.cs", mExportPath, mClassName);
            string content = stringBuilder.ToString();
            File.WriteAllText(path, content);
        }
    }
}
